package com.screwdriver.jso.processor.generator;

import com.screwdriver.jso.processor.utils.PropertyUtil;
import com.screwdriver.jso.processor.utils.TypeResolver;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.InterfaceDeclaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.ParameterDeclaration;
import com.sun.mirror.type.ClassType;
import com.sun.mirror.type.InterfaceType;
import com.sun.mirror.type.ReferenceType;
import com.sun.mirror.type.TypeMirror;

import java.util.Collection;

@SuppressWarnings("deprecation")
public class MethodSignatureGenerator {

    private final AnnotationProcessorEnvironment environment;

    public MethodSignatureGenerator(AnnotationProcessorEnvironment environment) {
        this.environment = environment;
    }

    public String generateMethodSignature(InterfaceDeclaration rootInterface, InterfaceType declaringSuperInterface, MethodDeclaration md) {
        return String.format("public final native %s %s(%s) %s %s",
                composeType(rootInterface, declaringSuperInterface, md.getReturnType()),
                md.getSimpleName(),
                composeParameters(rootInterface, declaringSuperInterface, md.getParameters()),
                composeThrowns(md),
                generateJSNICode(rootInterface, declaringSuperInterface, md));
    }

    public String composeType(InterfaceDeclaration rootInterface, InterfaceType declaringSuperInterface, TypeMirror type) {
        return new TypeResolver(environment, rootInterface, declaringSuperInterface, type).getParameterizedName();
    }


    private String composeParameters(InterfaceDeclaration rootInterface, InterfaceType declaringSuperInterface, Collection<ParameterDeclaration> parameters) {
        StringBuilder sb = new StringBuilder();
        int parameterCounter = 0;
        for (ParameterDeclaration pd : parameters) {
            if (parameterCounter > 0)
                sb.append(", ");

            sb.append(composeType(rootInterface, declaringSuperInterface, pd.getType())).append(" ").append(pd.getSimpleName());
        }
        return sb.toString();
    }

    private String composeThrowns(MethodDeclaration md) {
        StringBuilder sb = new StringBuilder();
        int i = 0;
        for (ReferenceType rt : md.getThrownTypes()) {
            sb.append((i > 0 ? ", " : " ") + ((ClassType) rt).getDeclaration().getSimpleName());
            i++;
        }
        return sb.toString();
    }

    private String generateJSNICode(InterfaceDeclaration rootInterface, InterfaceType declaringSuperInterface, MethodDeclaration md) {
        TypeResolver returnType = new TypeResolver(environment, rootInterface, declaringSuperInterface, PropertyUtil.getPropertyType(md));
        String propertyName = PropertyUtil.getPropertyName(md);

        if (PropertyUtil.isSetter(md)) {
            return JSNIGenerator.generateSetter(propertyName, md.getParameters().iterator().next().getSimpleName(), returnType);
        } else if (PropertyUtil.isGetter(md)) {
            return JSNIGenerator.generateGetter(propertyName, returnType);
        } else {
            return "//dont know what to do with this property\n";
        }
    }


}
